﻿#include "pch.h"
#include "qgp/qgach.h"
#include "qgp/qgadpt.h"
#include "qgsmm_math.inl"
#include "qgsmm_ldr.h"

struct SMMVTX
{
	tpl::Vec3			pos;
	//tpl::Color			color;
	tpl::Vec2			coord;
	tpl::Vec3			norm;
	tpl::Vec3			tan;
	tpl::Vec3			bin;
};

struct SMMVTXWGT
{
	tpl::Vec3			pos;
	//tpl::Color			color;
	tpl::Vec2			coord;
	tpl::Vec3			norm;
	tpl::Vec3			tan;
	tpl::Vec3			bin;
	tpl::Vec4			indices;
	tpl::Vec4			weight;
};

//////////////////////////////////////////////////////////////////////////
// SMM
KIMPL_SUBCLASS(qgSmm, "Smm");

//
qgSmm::qgSmm()
	: super_type(QGSMMFRM_BONE)
{
	_BaseRoam(QGROAM_OBJ_3);
}

//
qgSmm::~qgSmm()
{
	for (auto it = _frms.begin() + 1; it != _frms.end(); ++it)
	{
		qgSmmFrame* frm = *it;
		kobj_unload(frm);
	}
}

//
bool qgSmm::Update(float adv)
{
	if (_frms.size() < 2)
	{
		_dcnt = 0;
		return false;
	}

	// 모션
	// 해야함

	UpdateTM();

	_dcnt = UpdateFrame(adv);

	UpdateSub(adv);

	return _dcnt != 0;
}

//
void qgSmm::Draw()
{
	for (auto it = _mshs.begin(); it != _mshs.end(); ++it)
	{
		qgSmmMesh* mesh = *it;
		if (mesh->IsVisible())
			mesh->Draw();
	}
}

//
kint qgSmm::UpdateFrame(float adv)
{
	kint draw = 0;

	for (auto it = _frms.begin() + 1; it != _frms.end(); ++it)
	{
		qgSmmFrame* frm = *it;
		frm->Update(adv);
		if (frm->IsVisible() && frm->GetFrameType() >= QGSMMFRM_MESH)
			draw++;
	}

	return draw;
}

//
void qgSmm::DrawOnly()
{
	for (auto it = _mshs.begin(); it != _mshs.end(); ++it)
	{
		qgSmmMesh* mesh = *it;
		if (mesh->IsVisible())
			mesh->DrawOnly();
	}
}

//
qgSmmFrameRef qgSmm::GetFrame(const char* name)
{
	ksize_t h = k_strihash(name);

	for (auto it = _frms.begin(); it != _frms.end(); ++it)
	{
		qgSmmFrame* frm = *it;
		if (frm->GetNHash() == h && frm->GetName() == name)
			return frm;
	}

	return NULL;
}

//
qgSmmFrameRef qgSmm::FindFrame(kint id)
{
	for (auto it = _frms.begin(); it != _frms.end(); ++it)
	{
		qgSmmFrame* frm = *it;
		if (frm->GetId() == id)
			return frm;
	}

	return NULL;
}

//
kint qgSmm::GetMaterialFlagNth(kint nth)
{
	// 오류 처리 안했음
	return _mtfs[nth];
}

//
qgTextureRef qgSmm::GetTextureNth(kint nth)
{
	// 오류 처리 안했음
	return _texs[nth];
}

//
qgSmmFrameRef qgSmm::GetFrameNth(kint nth)
{
	// 오류 처리 안했음
	return _frms[nth];
}

//
qgSmmFrameRef qgSmm::GetDummyNth(kint nth)
{
	// 오류 처리 안했음
	return _dmms[nth];
}

//
qgSmmBoneRef qgSmm::GetBoneNth(kint nth)
{
	// 오류 처리 안했음
	return _bons[nth];
}

//
qgSmmMeshRef qgSmm::GetMeshNth(kint nth)
{
	// 오류 처리 안했음
	return _mshs[nth];
}

//
qgSmm* qgSmm::New(kint id, const char* filename, kint flags)
{
	qgRdh* rdh = qgRdh::Instance;

	kint size;
	kbyte* data = (kbyte*)rdh->GetStub()->FileRead(filename, &size);

	if (!data)
		return NULL;

	qgSmm* self = kobj_new(qgSmm);
	if (!((qgSmmCreator*)self)->_PrivateRead520(data, size, 0, filename))
	{
		self->Unload();
		self = NULL;
	}

	k_delete(data);

	return self;
}


//////////////////////////////////////////////////////////////////////////
// 프레임
KIMPL_SUBCLASS(qgSmmFrame, "SmmFrame");

qgSmmFrame::qgSmmFrame(qgSmmFrameType frmtype)
	: _frmtype(frmtype)
{

}


//////////////////////////////////////////////////////////////////////////
// 뼈대
KIMPL_SUBCLASS(qgSmmBone, "SmmBone");

qgSmmBone::qgSmmBone(qgSmmFrameType frmtype)
	: super_type(frmtype)
{

}

bool qgSmmBone::Update(float adv)
{
	if (!super_type::Update(adv))
		return false;

	_cmbn = _subm * _calc;

	return true;
}


//////////////////////////////////////////////////////////////////////////
// 메시
KIMPL_SUBCLASS(qgSmmMesh, "SmmMesh");

qgSmmMesh::qgSmmMesh(qgSmmFrameType frmtype)
	: super_type(frmtype)
{
	_data = new qbSmmDrawData();

	_splr = qbStaticSplrState<QGFLTX_LINEAR>::GetPtr();
	_rasz = qbStaticRaszState<QGFILL_SOLID, QGCULL_BACK>::GetPtr();
	_blnd = qbStaticBlndState<QGMASK_RGBA, QGBLO_ADD, QGBLF_SA, QGBLF_SA_INV>::GetPtr();
}

qgSmmMesh::~qgSmmMesh()
{
	delete _data;
}

bool qgSmmMesh::Update(float adv)
{
	if (!super_type::Update(adv))
		return false;

	return true;
}

void qgSmmMesh::Draw()
{
	if (!_draw)
		return;

	qgRdh* rdh = qgRdh::Instance;

	for (kint i = 0; i < (kint)K_COUNTOF(_tex); i++)
	{
		rdh->SetTexture(i, _tex[i]);
		rdh->SetSplrState(i, _splr);
	}

	rdh->SetDhslState(qbStaticDhslState<true>::GetPtr());
	rdh->SetRaszState(_rasz);
	rdh->SetBlndState(_blnd);

	rdh->SetBufferIndex(_ib);
	rdh->SetBufferVertex(0, _vdraw);
	rdh->SetBufferVertex(1, _vnorm);
	rdh->SetBufferVertex(2, _vweight);

	rdh->SetShader(_shd, _lo);

	rdh->SetTM(QGTM_WORLD, _calc);

	rdh->DrawIndexed(QGTPG_TRI_LIST, _data->indexes);
}

void qgSmmMesh::DrawOnly()
{
	if (!_draw)
		return;

	qgRdh* rdh = qgRdh::Instance;

	rdh->SetDhslState(qbStaticDhslState<true>::GetPtr());
	rdh->SetRaszState(_rasz);
	rdh->SetBlndState(_blnd);

	rdh->SetBufferIndex(_ib);
	rdh->SetBufferVertex(0, _vdraw);
	rdh->SetBufferVertex(1, _vnorm);
	rdh->SetBufferVertex(2, _vweight);

	rdh->SetShader(_shd, _lo);

	rdh->SetTM(QGTM_WORLD, _calc);

	rdh->DrawIndexed(QGTPG_TRI_LIST, _data->indexes);
}

void qgSmmMesh::_GenerateMesh(qgSmm* smm)
{
#if 1
	if (_data->indexes == 0 || _data->vertices == 0)
	{
		_visible = false;
		_draw = false;
		return;
	}

	qgRdh* rdh = qgRdh::Instance;

	_ib.InitPtr(rdh->CreateBuffer(QGBUFFER_INDEX, sizeof(kint), _data->indexes, 0, &(*_data->_i.begin())));

	_vdraw.InitPtr(rdh->CreateBuffer(QGBUFFER_VERTEX, sizeof(SMMVTX), _data->vertices, 0));
	SMMVTX* v = (SMMVTX*)_vdraw->Map();
	for (kint i = 0; i < _data->vertices; i++)
	{
		v->pos = _data->_v[i];
		//v->color = tpl::Color(_data->_d[i]);
		v->coord = _data->_t[i];
		v->norm = tpl::Vec3(_data->_n[i].x, _data->_n[i].y, _data->_n[i].z);
		v->tan = _data->_a[i];
		v->bin = _data->_b[i];
		v++;
	}
	_vdraw->Unmap();

	if (_eid < smm->GetTextureCount())
		_tex[0] = smm->GetTextureNth(_eid);

	_draw = true;
#endif
}


//////////////////////////////////////////////////////////////////////////
// 스킨
KIMPL_SUBCLASS(qgSmmSkin, "SmmSkin");

qgSmmSkin::qgSmmSkin(qgSmmFrameType frmtype)
	: super_type(frmtype)
{
}

qgSmmSkin::~qgSmmSkin()
{
	k_delete(_pcmbn);
	k_delete(_pinds);
}

bool qgSmmSkin::Update(float adv)
{
	if (!super_type::Update(adv))
		return false;

	return true;
}

void qgSmmSkin::Draw()
{
	if (!_draw)
		return;

	qgRdh* rdh = qgRdh::Instance;

	//
	for (kint i = 1; i < _cmbns; i++)
		_pcmbn[i] = _local * (*_pinds[i]);

	rdh->SetPropWedge(_cmbns, _pcmbn);

	//
	for (kint i = 0; i < (kint)K_COUNTOF(_tex); i++)
	{
		rdh->SetTexture(i, _tex[i]);
		rdh->SetSplrState(i, _splr);
	}

	rdh->SetDhslState(qbStaticDhslState<true>::GetPtr());
	rdh->SetRaszState(_rasz);
	rdh->SetBlndState(_blnd);

	rdh->SetBufferIndex(_ib);
	rdh->SetBufferVertex(0, _vdraw);
	rdh->SetBufferVertex(1, _vnorm);
	rdh->SetBufferVertex(2, _vweight);

	rdh->SetShader(_shd, _lo);

	rdh->SetTM(QGTM_WORLD, tpl::Matrices::Identity);

	rdh->DrawIndexed(QGTPG_TRI_LIST, _data->indexes);
}

void qgSmmSkin::DrawOnly()
{
	if (!_draw)
		return;

	qgRdh* rdh = qgRdh::Instance;

	//
	for (kint i = 1; i < _cmbns; i++)
		_pcmbn[i] = _local * (*_pinds[i]);

	rdh->SetPropWedge(_cmbns, _pcmbn);

	rdh->SetDhslState(qbStaticDhslState<true>::GetPtr());
	rdh->SetRaszState(_rasz);
	rdh->SetBlndState(_blnd);

	rdh->SetBufferIndex(_ib);
	rdh->SetBufferVertex(0, _vdraw);
	rdh->SetBufferVertex(1, _vnorm);
	rdh->SetBufferVertex(2, _vweight);

	rdh->SetShader(_shd, _lo);

	rdh->SetTM(QGTM_WORLD, tpl::Matrices::Identity);

	rdh->DrawIndexed(QGTPG_TRI_LIST, _data->indexes);
}

void qgSmmSkin::_BuildCombine(kint count)
{
	_cmbns = count;
	_pcmbn = k_new(count, tpl::Mat4);
	_pinds = k_new(count, tpl::Mat4*);
	_insts |= 0x8000;
}

void qgSmmSkin::_GenerateMesh(qgSmm* smm)
{
	if (_data->indexes == 0 || _data->vertices == 0)
	{
		_visible = false;
		_draw = false;
		return;
	}

	qgRdh* rdh = qgRdh::Instance;

	_ib.InitPtr(rdh->CreateBuffer(QGBUFFER_INDEX, sizeof(kint), _data->indexes, 0, &(*_data->_i.begin())));

	_vdraw.InitPtr(rdh->CreateBuffer(QGBUFFER_VERTEX, sizeof(SMMVTXWGT), _data->vertices, 0));
	SMMVTXWGT* v = (SMMVTXWGT*)_vdraw->Map();
	for (kint i = 0; i < _data->vertices; i++)
	{
		v->pos = _data->_v[i];
		//v->color = tpl::Color(_data->_d[i]);
		v->coord = _data->_t[i];
		v->norm = tpl::Vec3(_data->_n[i].x, _data->_n[i].y, _data->_n[i].z);
		v->tan = _data->_a[i];
		v->bin = _data->_b[i];
		v->indices = tpl::Vec4(_data->_w[i].i[0], _data->_w[i].i[1], _data->_w[i].i[2], _data->_w[i].i[3]);
		v->weight = tpl::Vec4(_data->_w[i].w[0], _data->_w[i].w[1], _data->_w[i].w[2], _data->_w[i].w[3]);
		v++;
	}
	_vdraw->Unmap();

	_tex[0] = smm->GetTextureNth(_eid);
	kobj_load(_tex[0]);

	_draw = true;

	for (kint i = 0; i < _cmbns; i++)
	{
		qgSmmBone* b = smm->GetBoneNth(i);
		_pinds[i] = &b->_cmbn;
	}
}




